#include "risk/risk_rules.h"
#include <cmath>
#include <sstream>

namespace hft {

// MaxPositionRule implementation
MaxPositionRule::MaxPositionRule(double maxPositionValue) 
    : max_position_value_(maxPositionValue) {}

RiskCheckResult MaxPositionRule::checkOrder(const Order& order) {
    double newPositionValue = current_positions_[order.symbol];
    if (order.side == OrderSide::Buy) {
        newPositionValue += order.price * order.volume;
    } else {
        newPositionValue -= order.price * order.volume;
    }

    if (std::abs(newPositionValue) > max_position_value_) {
        std::stringstream ss;
        ss << "Position value " << std::abs(newPositionValue) 
           << " would exceed max position value " << max_position_value_;
        return RiskCheckResult(false, ss.str());
    }
    return RiskCheckResult(true);
}

RiskCheckResult MaxPositionRule::checkPosition(const Position& position) {
    double positionValue = std::abs(position.volume * position.avg_price);
    if (positionValue > max_position_value_) {
        std::stringstream ss;
        ss << "Current position value " << positionValue 
           << " exceeds max position value " << max_position_value_;
        return RiskCheckResult(false, ss.str());
    }
    return RiskCheckResult(true);
}

void MaxPositionRule::update(double pnl, double equity) {
    // Position values are updated through checkOrder
}

void MaxPositionRule::reset() {
    current_positions_.clear();
}

// MaxOrderSizeRule implementation
MaxOrderSizeRule::MaxOrderSizeRule(double maxOrderSize) 
    : max_order_size_(maxOrderSize) {}

RiskCheckResult MaxOrderSizeRule::checkOrder(const Order& order) {
    double orderValue = order.price * order.volume;
    if (orderValue > max_order_size_) {
        std::stringstream ss;
        ss << "Order value " << orderValue 
           << " exceeds max order size " << max_order_size_;
        return RiskCheckResult(false, ss.str());
    }
    return RiskCheckResult(true);
}

RiskCheckResult MaxOrderSizeRule::checkPosition(const Position& position) {
    return RiskCheckResult(true); // Not applicable for order size rule
}

void MaxOrderSizeRule::update(double pnl, double equity) {
    // No update needed for order size rule
}

void MaxOrderSizeRule::reset() {
    // No reset needed for order size rule
}

// MaxLeverageRule implementation
MaxLeverageRule::MaxLeverageRule(double maxLeverage) 
    : max_leverage_(maxLeverage), current_equity_(0) {}

RiskCheckResult MaxLeverageRule::checkOrder(const Order& order) {
    double newPositionValue = position_values_[order.symbol];
    if (order.side == OrderSide::Buy) {
        newPositionValue += order.price * order.volume;
    } else {
        newPositionValue -= order.price * order.volume;
    }

    double totalPositionValue = 0;
    for (const auto& [symbol, value] : position_values_) {
        if (symbol != order.symbol) {
            totalPositionValue += std::abs(value);
        }
    }
    totalPositionValue += std::abs(newPositionValue);

    double leverage = totalPositionValue / current_equity_;
    if (leverage > max_leverage_) {
        std::stringstream ss;
        ss << "Leverage " << leverage 
           << " would exceed max leverage " << max_leverage_;
        return RiskCheckResult(false, ss.str());
    }
    return RiskCheckResult(true);
}

RiskCheckResult MaxLeverageRule::checkPosition(const Position& position) {
    double totalPositionValue = 0;
    for (const auto& [symbol, value] : position_values_) {
        totalPositionValue += std::abs(value);
    }

    double leverage = totalPositionValue / current_equity_;
    if (leverage > max_leverage_) {
        std::stringstream ss;
        ss << "Current leverage " << leverage 
           << " exceeds max leverage " << max_leverage_;
        return RiskCheckResult(false, ss.str());
    }
    return RiskCheckResult(true);
}

void MaxLeverageRule::update(double pnl, double equity) {
    current_equity_ = equity;
}

void MaxLeverageRule::reset() {
    position_values_.clear();
}

// MaxDrawdownRule implementation
MaxDrawdownRule::MaxDrawdownRule(double maxDrawdownPercent) 
    : max_drawdown_percent_(maxDrawdownPercent), peak_equity_(0), current_equity_(0) {}

RiskCheckResult MaxDrawdownRule::checkOrder(const Order& order) {
    return RiskCheckResult(true); // Drawdown is checked in update
}

RiskCheckResult MaxDrawdownRule::checkPosition(const Position& position) {
    return RiskCheckResult(true); // Drawdown is checked in update
}

void MaxDrawdownRule::update(double pnl, double equity) {
    current_equity_ = equity;
    if (equity > peak_equity_) {
        peak_equity_ = equity;
    }

    if (peak_equity_ > 0) {
        double drawdown = (peak_equity_ - current_equity_) / peak_equity_ * 100.0;
        if (drawdown > max_drawdown_percent_) {
            std::stringstream ss;
            ss << "Current drawdown " << drawdown 
               << "% exceeds max drawdown " << max_drawdown_percent_ << "%";
            throw std::runtime_error(ss.str());
        }
    }
}

void MaxDrawdownRule::reset() {
    peak_equity_ = current_equity_;
}

// MaxDailyLossRule implementation
MaxDailyLossRule::MaxDailyLossRule(double maxDailyLoss) 
    : max_daily_loss_(maxDailyLoss), daily_pnl_(0), start_equity_(0) {}

RiskCheckResult MaxDailyLossRule::checkOrder(const Order& order) {
    return RiskCheckResult(true); // Daily loss is checked in update
}

RiskCheckResult MaxDailyLossRule::checkPosition(const Position& position) {
    return RiskCheckResult(true); // Daily loss is checked in update
}

void MaxDailyLossRule::update(double pnl, double equity) {
    if (start_equity_ == 0) {
        start_equity_ = equity;
    }
    daily_pnl_ = equity - start_equity_;

    if (-daily_pnl_ > max_daily_loss_) {
        std::stringstream ss;
        ss << "Daily loss " << -daily_pnl_ 
           << " exceeds max daily loss " << max_daily_loss_;
        throw std::runtime_error(ss.str());
    }
}

void MaxDailyLossRule::reset() {
    daily_pnl_ = 0;
    start_equity_ = 0;
}

} // namespace hft